#pragma once

#include <iostream>
#include "stack.hpp"
#include "string.hpp"
#include "vector.hpp"
#include "operation.hpp"

using namespace Simulation;

class Calc
{
public:
    Calc(const string &exper)
        : _exper(exper)
    {
    }
    double GetResult()
    {
        Split();
        ConvertSuffixExpression();

        return evalRPN();
    }

private:
    double evalRPN()
    {
        stack<double> s;
        double num1, num2;
        for (auto &e : _polishExper)
        {
            if (e == "+" || e == "-" || e == "*" || e == "/")
            {
                num1 = s.top();
                s.pop();
                num2 = s.top();
                s.pop();
            }
            else
            {
                s.push(atof(e.c_str()));
            }
            if (e == "+")
            {
                s.push(num1 + num2);
            }
            else if (e == "-")
            {
                s.push(num2 - num1);
            }
            else if (e == "*")
            {
                s.push(num1 * num2);
            }
            else if (e == "/")
            {
                if (num1 == 0)
                {
                    std::cout << "除0错误" << std::endl;
                    exit(-1);
                }
                s.push(num2 / num1);
            }
        }
        return s.top();
    }
    void Split()
    {
        string num;
        for (auto ch : _exper)
        {
            if (ch == ' ')
                continue;
            if (ch == '(' || ch == ')' || ch == '+' || ch == '-' || ch == '*' || ch == '/')
            {
                if (num != "")
                {
                    _v.push_back(num);
                    num.clear();
                }
                _v.push_back(string() + ch);
            }
            else
            {
                num += ch;
            }
        }
        if (num != "")
        {
            _v.push_back(num);
            num.clear();
        }
    }
    // 转后缀表达式
    void ConvertSuffixExpression()
    {
        for (auto &str : _v)
        {
            // 数字
            if ((str.size() == 1 && str[0] == '0') || (str[0] > '0' && str[0] <= '9'))
            {
                _polishExper.push_back(str);
            }
            else if (str == "(")
            {
                _opSt.push('(');
            }
            else if (str == ")")
            {
                // 将栈里面的符号取出并加入逆波兰表达式中
                while (_opSt.top() != '(')
                {
                    _polishExper.push_back(string() + _opSt.top());
                    _opSt.pop();
                }
                _opSt.pop(); // 弹出左括号
            }
            else
            {
                // 操作符
                // 当前运算符优先级低且栈不为空
                while (!_opSt.empty() && !_oper.greater(str[0], _opSt.top()))
                {
                    _polishExper.push_back(string() + _opSt.top());
                    _opSt.pop();
                }
                // 该符号入栈
                _opSt.push(str[0]);
            }
        }
        // 剩余符号全部入逆波兰表达式
        while (!_opSt.empty())
        {
            _polishExper.push_back(string() + _opSt.top());
            _opSt.pop();
        }
    }

private:
    Operation _oper;
    stack<char> _opSt;           // 符号栈
    string _exper;               // 字符串表达式
    vector<string> _v;           // 用来存放拆分好的数字和操作符
    vector<string> _polishExper; // 存放转换好的逆波兰表达式
};
